package com.rytong.tools.httpconnect;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import com.rytong.tools.ui.Component;
import com.rytong.tools.ui.LPAlertDialog;
import com.rytong.tools.ui.WaitProgressDialog;
import com.rytong.tools.utils.Utils;
import android.app.Activity;
import android.app.Dialog;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.Window;

public class WaitDialog {
    /**
     * Progress indictor image.
     */
    public static Bitmap progress_;
    protected static Activity activity_;
    /**
     * This is how often we allow caller to update WaitDialog. See Checker class.
     */
    public final static int TIMEOUT = 200; // Milliseconds
    private final String CANCEL = "取消";

    private TextHandler handler_;
    protected int waiterTimeout_;
    private String text_;
    private int processingCtr_;
    static WaitProgressDialog progressdialog_;
    static Dialog dialog_;
    Checker checker_;
    private int running_;

    private static final int NUM_THREADS = 2;

    /**
     * Remembers last display to go to after the dialog is done.
     */

    private boolean firstPaint_ = false;;
    private final Vector queue_ = new Vector(2);
    private boolean stopped_ = false;
    private boolean checkerStopped_ = false;
    private Task displayTask_;

    boolean isNoCancel_ = false; // Indicate that the wait dialog don't have

    // cancel action when it is true.

    public WaitDialog() {
        waiterTimeout_ = TIMEOUT;
        processingCtr_ = 0;
        running_ = 0;
        handler_ = new TextHandler();
        initWorkQueue();
    }

    void notifyHttpChecker() {
        synchronized (this) {
            if (checker_ == null || !checker_.isAlive()) {
                checker_ = new Checker(this);
                checker_.start();
            } else {
                this.notify();
            }
        }
    }

    /**
     * Called from the checker thread when task finishes.
     */
    private void done(Task task) {
        // 取消进度条显示
        // WaitDialog.Task.cancelProgressBar();
        setText("正在初始化界面");
        displayTask_.totalSize_ = 0;
        handler_.onUpdate(this);
        if (task.isStop())
            return;
        if (task.hasFailed()) {
            task.onFailure(this);
        } else {
            task.onSuccess(this);
        }
        // NOTE: don't set checker_ or waiter_ to null here. We may
        // erase the jobs that the next wait dialog has started.
    }

    /**
     * Default handler with text message display.
     */
    protected static class TextHandler {
        protected int ctr_;

        public TextHandler() {
            ctr_ = 0;
        }

        public void onUpdate(WaitDialog dlg) {
            // Since dialog's text may change, we can't use str_ here.
            final WaitDialog dlgTemp = dlg;
            dlgTemp.setProcessingCtr(ctr_);
            if (ctr_++ > 5) {
                ctr_ = 0;
            }
            if (null == activity_)
                return;
            activity_.runOnUiThread(new Runnable() {

                public void run() {
                    // TODO Auto-generated method stub
                    if (null != progressdialog_)
                        progressdialog_.setMessage(dlgTemp.getLoadingStatus());
                }

            });

        }
    }

    String getLoadingStatus() {
        if (null == displayTask_ || displayTask_.totalSize_ == 0 || displayTask_.totalSize_ == -1) {
            return text_;
        } else {
            String status;
            int progress = 100 * displayTask_.finishSize_ / displayTask_.totalSize_;
            StringBuffer buf = new StringBuffer();
            buf.append(text_);
            buf.append(": ");
            buf.append(progress);
            buf.append("%");
            status = buf.toString();
            return status;
        }
    }

    private void initWorkQueue() {
        int num = NUM_THREADS;
        if (num > 1) {
            num--;
            new Worker(this, 0).start();// This worker only for task.priority =
            // 0.
        }
        for (int i = 0; i < num; i++) {
            new Worker(this, 100000).start();
        }
    }

    private static class Worker extends Thread {
        private final WaitDialog dlg_;
        private int prio_;// This thread only deal with the task who's priority

        // not bigger than prio_.

        Worker(WaitDialog dlg, int priority) {
            super();
            dlg_ = dlg;
            prio_ = priority;
        }

        public void run() {
            Task task;
            for (;;) {
                try {
                    sleep(50);
                } catch (InterruptedException ex) {
                }
                // Get a task from the queue
                synchronized (dlg_.queue_) {
                    try {
                        while (!dlg_.stopped_ && dlg_.queue_.isEmpty())
                            dlg_.queue_.wait();
                    } catch (InterruptedException e) {
                        // Ignore interrupts while we were idle. If someone
                        // really wants
                        // us to stop, she must call stop()!
                    }
                    if (dlg_.stopped_)
                        return;
                    if (dlg_.queue_.isEmpty()) {
                        // We must have got interrupted from the wait() loop
                        // while having
                        // no jobs at all. Go back to wait.
                        continue;
                    } else {
                        task = (Task) dlg_.queue_.firstElement();
                        // only deal with who's priority not bigger than prio_
                        if (task.priority_ > prio_) {
                            // notify other thread which wait for this. if not
                            // will lead to dead lock.
                            dlg_.queue_.notifyAll();
                            continue;
                        }
                        dlg_.queue_.removeElementAt(0);
                        if (task.isStop())
                            continue;
                    }
                }
                synchronized (dlg_) {
                    ++dlg_.running_;
                }
                boolean done = false;
                try {
                    dlg_.notifyHttpChecker();
                    task.mainEntrance(dlg_);
                    // The cleanup of a task will run from the main thread.
                    final Task t = task;
                    // 原项目该操作为另起线程
                    new Thread() {
                        public void run() {
                            dlg_.done(t);
                        }
                    }.start();
                    // /////////////////////
                    done = true;
                } finally {
                    synchronized (dlg_) {
                        --dlg_.running_;
                    }
                    if (!done) {
                        // should not throw any exception, but may be
                        // interrupted
                        // by runtime or other errors. When that happens, we
                        // detect that by the
                        // done flag, and let this thread terminate, and start a
                        // new one to replace.
                        new Worker(dlg_, prio_).start();
                        break;
                    }
                }
            }
        }
    }

    /**
     * Instance inner class to periodically check waiter thread status and update UI if available.
     */
    private class Checker extends Thread {
        private final WaitDialog dlg_;

        public Checker(WaitDialog dlg) {
            super();
            dlg_ = dlg;
        }

        public void run() {
            while (true) {
                try {
                    sleep(waiterTimeout_);
                } catch (InterruptedException ex) {
                    // Ignore and continue to wait.
                }
                synchronized (dlg_) {
                    try {
                        while (dlg_.running_ <= 0 && !dlg_.checkerStopped_)
                            dlg_.wait();
                    } catch (InterruptedException ignored) {
                    }
                    if (dlg_.checkerStopped_)
                        return;
                }
                handler_.onUpdate(dlg_);
            }
        }
    }

    /**
     * Modeled after CancellableTask, this class does not depends on Executable nor Runnable but offers similar
     * functionality. It is intended to be extended as anonymous classes when calling startTask(), and caller should
     * define run().
     */
    public abstract static class Task {
        protected Exception exception_ = null;
        protected String errmsg_ = null;
        protected String name_;
        protected int priority_;
        private int totalSize_ = -1;
        private int finishSize_;
        boolean stop_;

        public Task(int priority) {
            name_ = null;
            priority_ = priority;
            stop_ = false;
        }

        public Task(String name, int priority) {
            name_ = name;
            priority_ = priority;
            stop_ = false;
        }

        public void setTotalSize(int total) {
            totalSize_ = total;
            finishSize_ = 0;
        }

        public void updateFinish(int finish) {
            finishSize_ += finish;
        }

        public String getErrMsg() {
            if (errmsg_ == null && exception_ != null)
                return exception_.toString();
            else
                return errmsg_;
        }

        public Exception getException() {
            return exception_;
        }

        public boolean hasFailed() {
            return (exception_ != null || errmsg_ != null);
        }

        void setException(Exception e) {
            exception_ = e;
        }

        public void setErrMsg(String msg) {
            errmsg_ = msg;
        }

        public void setErrMsg(Exception e) {
            errmsg_ = (e == null) ? null : e.getMessage();
        }

        /**
         * This is the main entrance point so that if any exception leaks out of run(), we'll capture it here and set
         * error msg accordingly.
         */
        void mainEntrance(WaitDialog dlg) {
            try {
                run(dlg);
            } catch (Exception ex) {
                setErrMsg(ex);
                setException(ex);
                Utils.printException(ex);
                cancelProgressBar(activity_);
            } catch (Throwable ex) {
                // In case something implementation-specific leaked out.
                setErrMsg(ex.getMessage());
                cancelProgressBar(activity_);
            }
        }

        /**
         * We do not use Runnable::run() so that we can throw exceptions. We had to throw the very basic exception
         * because we don't know what are out there.
         */
        abstract public void run(WaitDialog dlg) throws Exception;

        public void onSuccess(WaitDialog dlg) {
            // 取消进度条显示
            cancelProgressBar(activity_);
        }

        public void onFailure(WaitDialog dlg) {
            // 取消进度条显示
            cancelProgressBar(activity_);
        }

        /**
         * @param stop_
         *            the stop_ to set
         */
        public void setStop(boolean stop_) {
            this.stop_ = stop_;
        }

        /**
         * @return the stop_
         */
        public boolean isStop() {
            return stop_;
        }
    }

    void setProcessingCtr(int i) {
        processingCtr_ = i;
    }

    public boolean removeTask(String name) {
        synchronized (queue_) {
            for (int i = 0; i < queue_.size(); i++) {
                Task task = (Task) queue_.elementAt(i);
                if (task.name_ != null && task.name_.equals(name)) {
                    queue_.removeElementAt(i);
                    return true;
                }
            }
            return false;
        }
    }

    public void setText(String t) {
        text_ = t;
    }

    /**
     * Adds a background task who's run() method will be invoked asynchronously by a worker thread.
     */
    public void addBgTask(Task task) {
        // 在该处重新赋值改变量
        displayTask_ = task;

        if (task == null) {
            return;
        }
        synchronized (queue_) {
            if (stopped_) {
                return;
            }
            boolean flag = true;
            for (int i = queue_.size() - 1; i >= 0; i--) {
                Task temp = (Task) queue_.elementAt(i);
                if (task.priority_ >= temp.priority_) {
                    queue_.insertElementAt(task, i + 1);
                    flag = false;
                    break;
                }
            }
            if (flag)
                queue_.insertElementAt(task, 0);
            queue_.notify();
        }
    }

    /**
     * Indicate that the wait dialog don't have cancel action when it is true. This wait dialog is a full screen dialog.
     */
    public void addFgTask(Activity bv, Dialog dialog, int dialogW, int dialogH, int gravity, Task task,
            boolean isPartScreen, boolean isNoCancel) {
        addFgTask(bv, dialog, dialogW, dialogH, gravity, task);
        isNoCancel_ = isNoCancel;
    }

    private Bitmap getImageFromAssetFile(Activity activity, String fileName) {
        Bitmap image = null;
        try {
            AssetManager am = activity.getAssets();
            InputStream is = am.open(fileName);
            image = BitmapFactory.decodeStream(is);
            is.close();
        } catch (Exception e) {

        }
        return image;
    }

    // 取消已存在的进度条显示
    public static void cancelProgressBar(Activity activity) {
        if (null != dialog_) {
            if (dialog_.isShowing()) {
                if (!activity.isFinishing()) {
                    dialog_.dismiss();
                    dialog_ = null;
                }
            }
        }
        if (null != progressdialog_) {
            if (progressdialog_.isShowing()) {
                if (!activity.isFinishing()) {
                    progressdialog_.dismiss();
                }
            }
            progressdialog_ = null;
        }
        if (null != Component.DIALOGHASH) {
            int size = Component.DIALOGHASH.size();
            LPAlertDialog dialog = null;
            if (size > 0) {
                Iterator iter = Component.DIALOGHASH.entrySet().iterator();
                Map.Entry entry = null;
                Object key = null;
                Field field = null;
                while (iter.hasNext()) {
                    entry = (Map.Entry) iter.next();
                    key = entry.getKey();
                    dialog = (LPAlertDialog) entry.getValue();
                    if (dialog.isShowing() && dialog.getTitle().equalsIgnoreCase(Component.PROGRESSDIALOG)) {
                        dialog.dismiss();
                        Component.DIALOGHASH.remove(key);
                        return;
                    }
                }
            }
        }
    }

    /**
     * Adds a foreground task who's run() method will be invoked asynchronously by a worker thread.
     * 
     * @param Activity
     *            界面参数
     * @param Dialog
     *            需要显示的进度提示框（如果为null，则会启用默认的进度提示框）
     * @param dialogW
     *            进度提示框的宽度
     * @param dialogH
     *            进度提示框的高度
     * @param grivaty
     *            界面布局参数（Gravity.CENTER等）
     * @param task
     *            任务参数
     */
    public void addFgTask(final Activity activity, Dialog dialog, int dialogW, int dialogH, int gravity, Task task) {
        activity_ = activity;
        //使用自定义dialog，此处不需要解析图片
        //int resourcesId = Utils.getResourcesId(activity, "progress", "drawable");
        //progress_ = Utils.getBitmap(resourcesId, activity);
        isNoCancel_ = false; // init to false everytime.
        displayTask_ = task;
        displayTask_.totalSize_ = -1;
        displayTask_.finishSize_ = 0;
        displayTask_.setStop(false);
        cancelProgressBar(activity);
        setText("正在获取数据");
        if (null != dialog)
            dialog_ = dialog;
        if (null == dialog_) {
            // 后台未传dialog控件,则使用默认的progressdialog_
            if (!activity.isFinishing()) {
	        	if(null == progressdialog_){
	        		progressdialog_ = new WaitProgressDialog(activity, displayTask_);                    		
	        	}
	        	progressdialog_.show(getLoadingStatus());
            }
        } else {
            dialog_.setCanceledOnTouchOutside(false);
            // 设置dialog位置
            Window mWindow = dialog_.getWindow();
            // 使对话框位于屏幕居中
            mWindow.setGravity(gravity);
            // 使对话框适应子元素大小
            mWindow.setLayout(dialogW, dialogH);
            if (!activity.isFinishing())
                dialog_.show();
        }
        firstPaint_ = true;
        addBgTask(task);
    }
    
    /**
     * Adds a foreground task who's run() method will be invoked asynchronously by a worker thread.
     * 
     * @param Activity
     *            界面参数
     * @param Dialog
     *            需要显示的进度提示框（如果为null，则会启用默认的进度提示框）
     * @param dialogW
     *            进度提示框的宽度
     * @param dialogH
     *            进度提示框的高度
     * @param grivaty
     *            界面布局参数（Gravity.CENTER等）
     * @param isGone
     * 			     返回键屏蔽参数           
     * @param task
     *            任务参数
     */
    public void addFgTask(final Activity activity, Dialog dialog, int dialogW, int dialogH, int gravity, boolean isGone, Task task) {
    	activity_ = activity;
    	//使用自定义dialog，此处不需要解析图片
    	//int resourcesId = Utils.getResourcesId(activity, "progress", "drawable");
    	//progress_ = Utils.getBitmap(resourcesId, activity);
    	isNoCancel_ = false; // init to false everytime.
    	displayTask_ = task;
    	displayTask_.totalSize_ = -1;
    	displayTask_.finishSize_ = 0;
    	displayTask_.setStop(false);
    	cancelProgressBar(activity);
    	setText("正在获取数据");
    	if (null != dialog)
    		dialog_ = dialog;
    	if (null == dialog_) {
    		// 后台未传dialog控件,则使用默认的progressdialog_
    		if (!activity.isFinishing()) {
    			if(null == progressdialog_){
    				progressdialog_ = new WaitProgressDialog(activity, displayTask_);
    			}
    			progressdialog_.show(getLoadingStatus(), isGone);
    		}
    	} else {
    		dialog_.setCanceledOnTouchOutside(false);
    		// 设置dialog位置
    		Window mWindow = dialog_.getWindow();
    		// 使对话框位于屏幕居中
    		mWindow.setGravity(gravity);
    		// 使对话框适应子元素大小
    		mWindow.setLayout(dialogW, dialogH);
    		if (!activity.isFinishing())
    			dialog_.show();
    	}
    	firstPaint_ = true;
    	addBgTask(task);
    }

    /**
     * 该方法指示单纯的显示进度条
     * 
     * @param activity
     *            进度条被加载的界面
     */
    public void showProgressdialog(Activity activity) {
    	if(null != displayTask_){
    		displayTask_.setStop(false);    		
    	}
        cancelProgressBar(activity);
        if (!activity.isFinishing()) {
        	if(null == progressdialog_){
        		progressdialog_ = new WaitProgressDialog(activity, displayTask_);
        	}
        	progressdialog_.show(getLoadingStatus());
        }
    }

    /**
     * Display a progress indicator.
     */
    public final void drawProcessing(Canvas g, int centerX, int centerY) {
        Paint paint = new Paint();
        g.clipRect(centerX, centerY, centerX + 50, centerY + 5);
        g.drawBitmap(progress_, centerX, centerY, paint);
        g.clipRect(new Rect(centerX + processingCtr_ * 9, centerY, centerX + processingCtr_ * 9 + 50 - processingCtr_
                * 9, centerY + 5));
        g.drawBitmap(progress_, centerX + processingCtr_ * 9, centerY, paint);
        g.clipRect(centerX, centerY, centerX + 50, centerY + 5);
        g.drawBitmap(progress_, centerX - (54 - processingCtr_ * 9), centerY, paint);

        g.clipRect(0, 0, Component.SCREENWIDTH, Component.SCREENHEIGHT);
    }

    public void cancelAndRemoveTask(String taskName) {
        displayTask_.setStop(true);
        removeTask(taskName);
        // mid_.bocChannelEntity_.cleanClonePoiRepository();
    }
    
    /**
     * 获得当前任务的状态。
     * @return 当前任务的状态。
     */
    public boolean getDisplayTaskStatus () {
        return displayTask_.stop_;
    }
    
    /**
     * 设置当前任务的状态。
     * @param stop 待设置的任务状态。
     */
    public void setDisplayTaskStatus (Boolean stop) {
        displayTask_.stop_ = stop;
    }
}
